<template><div><h2 id="用户授权" tabindex="-1"><a class="header-anchor" href="#用户授权"><span>用户授权</span></a></h2>
<ul>
<li><a href="#introduction">简介</a></li>
<li><a href="#gates">拦截器</a>
<ul>
<li><a href="#writing-gates">编写拦截器</a></li>
<li><a href="#authorizing-actions-via-gates">授权动作</a></li>
<li><a href="#gate-responses">拦截器响应</a></li>
<li><a href="#intercepting-gate-checks">拦截器拦截检查</a></li>
<li><a href="#inline-authorization">内联授权</a></li>
</ul>
</li>
<li><a href="#creating-policies">创建策略</a>
<ul>
<li><a href="#generating-policies">生成策略</a></li>
<li><a href="#registering-policies">注册策略</a></li>
</ul>
</li>
<li><a href="#writing-policies">编辑策略</a>
<ul>
<li><a href="#policy-methods">策略模型</a></li>
<li><a href="#policy-responses">策略返回</a></li>
<li><a href="#methods-without-models">不使用模型的方法</a></li>
<li><a href="#guest-users">访客和用户</a></li>
<li><a href="#policy-filters">策略的过滤器</a></li>
</ul>
</li>
<li><a href="#authorizing-actions-using-policies">使用策略进行授权操作</a>
<ul>
<li><a href="#via-the-user-model">通过用户模型</a></li>
<li><a href="#via-controller-helpers">通过控制器辅助函数</a></li>
<li><a href="#via-middleware">通过中间件</a></li>
<li><a href="#via-blade-templates">通过 Blade 模板</a></li>
<li><a href="#supplying-additional-context">以附加形式提供给上下文调用</a></li>
</ul>
</li>
</ul>
<h2 id="简介" tabindex="-1"><a class="header-anchor" href="#简介"><span>简介</span></a></h2>
<p>除了提供内置的 <a href="https://learnku.com/docs/laravel/10.x/authentication" target="_blank" rel="noopener noreferrer">authentication</a>（身份验证）服务外，Laravel 还提供了一种可以很简单就进行使用的方法，来对用户与资源的授权关系进行管理。 它很安全，即使用户已经通过了「身份验证（authentication)」, 用户也可能无权对应用程序中重要的模型或数据库记录进行删除或更改。简单、条理化的系统性，是 Laravel 对授权管理的特性。</p>
<p>Laravel 主要提供了两种授权操作的方法: <a href="#gates">拦截器</a>和<a href="#creating-policies">策略</a>。 可以把拦截器（gates）和策略（policies）想象成路由和控制器。拦截器（Gates）提供了一种轻便的基于闭包函数的授权方法，像是路由。而策略（policies)，就像是一个控制器，对特定模型或资源，进行分组管理的逻辑规则。 在本文档中，我们将首先探讨拦截器（gates），然后研究策略（policies)。</p>
<p>你在构建应用程序时，不用为是仅仅使用拦截器（gates）或是仅仅使用策略（policies）而担心，并不需要在两者中进行唯一选择。大多数的应用程序都同时包含两个方法，并且同时使用两者，能够更好的进行工作。拦截器（gates），更适用于没有与任何模型或资源有关的授权操作，例如查看管理员仪表盘。与之相反，当你希望为特定的模型或资源进行授权管理时，应该使用策略（policies) 方法。</p>
<h2 id="拦截器-gates" tabindex="-1"><a class="header-anchor" href="#拦截器-gates"><span>拦截器 (Gates)</span></a></h2>
<h3 id="编写拦截器-gates" tabindex="-1"><a class="header-anchor" href="#编写拦截器-gates"><span>编写拦截器（Gates）</span></a></h3>
<blockquote>
<p><strong>注意</strong><br>
通过理解拦截器（Gates），是一个很好的学习 Laravel 授权特性的基础知识的方法。同时，考虑到 Laravel 应用程序的健壮性，应该结合使用策略 <a href="#creating-policies">policies</a> 来组织授权规则。</p>
</blockquote>
<p>拦截器（Gates）是用来确定用户是否有权执行给定操作的闭包函数。默认条件下，拦截器（Gates）的使用，是在<code v-pre>App\Providers\AuthServiceProvider</code>类中的 <code v-pre>boot</code> 函数里来规定<code v-pre>Gate</code>规则。拦截器（Gates）始终接收用户实例为其第一个参数，并且可以选择性的接收其他参数，例如相关的 Eloquent 模型。</p>
<p>在下面的例子中，我们将定义一个拦截器（Gates)，并通过调用<code v-pre>App\Models\Post</code>类，来实现结合用户的 POST 请求，命中给定的规则。拦截器（Gates）将通过比较用户的<code v-pre>id</code>，和 POST 请求中的<code v-pre>user_id</code>来实现这个目标：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 注册任何需要身份验证、授权服务的行为</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>像是在控制器中操作一样，也可以直接使用类，进行回调数组，完成拦截器（Gates）的定义：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Policies<span class="token punctuation">\</span>PostPolicy</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 注册任何需要身份验证、授权服务的行为</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name static-context">PostPolicy</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'update'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="授权动作" tabindex="-1"><a class="header-anchor" href="#授权动作"><span>授权动作</span></a></h3>
<p>如果需要通过拦截器（Gates）来对行为进行授权控制，你可以通过调用<code v-pre>Gate</code>中的<code v-pre>allows</code>或<code v-pre>denies</code>方法。请注意，在使用过程中，你不需要将已经通过身份验证的用户信息传递给这些方法。 Laravel 将会自动把用户信息传递给拦截器（Gates）。以下是一个典型的，在控制器中使用拦截器（Gates）进行行为授权控制的例子：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 更新给定的帖子</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span> <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">allows</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token function">abort</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 更新帖子...</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你需要判断某个用户，是否有权执行某个行为，你可以在<code v-pre>Gate</code>门面中，使用<code v-pre>forUser</code>方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">forUser</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">allows</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 这个用户可以提交update...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">forUser</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">denies</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 这个用户不可以提交update...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你还可以通过<code v-pre>any</code>或<code v-pre>none</code>方法来一次性授权多个行为:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">any</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'delete-post'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户可以提交update或delete...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">none</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'delete-post'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户不可以提交update和delete...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="未通过授权时的抛出异常" tabindex="-1"><a class="header-anchor" href="#未通过授权时的抛出异常"><span>未通过授权时的抛出异常</span></a></h4>
<p><code v-pre>Illuminate\Auth\Access\AuthorizationException</code>中准备了 HTTP 的 403 响应。你可以使用<code v-pre>Gate</code>门面中的<code v-pre>authorize</code>方法，来规定如果用户进行了未授权的行为时，触发<code v-pre>AuthorizationException</code>实例 ，该实例会自动转换返回为 HTTP 的 403 响应:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 行为已获授权...</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="上下文的值传递" tabindex="-1"><a class="header-anchor" href="#上下文的值传递"><span>上下文的值传递</span></a></h4>
<p>能够用于拦截器（Gates）的授权方法，(<code v-pre>allows</code>，<code v-pre>denies</code>，<code v-pre>check</code>，<code v-pre>any</code>，<code v-pre>none</code>， <code v-pre>authorize</code>，<code v-pre>can</code>，<code v-pre>cannot</code>) 和在前端进行的授权方法 <a href="#via-blade-templates">Blade 指令</a> (<code v-pre>@can</code>，<code v-pre>@cannot</code>，<code v-pre>@canany</code>) 在第 2 个参数中，可以接收数组。这些数组元素作为参数传递给拦截器（Gates），在做出授权决策时可用于其他上下文:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Category</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create-post'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Category</span> <span class="token variable">$category</span><span class="token punctuation">,</span> <span class="token keyword type-hint">bool</span> <span class="token variable">$pinned</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">canPublishToGroup</span><span class="token punctuation">(</span><span class="token variable">$category</span><span class="token operator">-></span><span class="token property">group</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">false</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span> <span class="token keyword">elseif</span> <span class="token punctuation">(</span><span class="token variable">$pinned</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">canPinPosts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">false</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">check</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create-post'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token variable">$category</span><span class="token punctuation">,</span> <span class="token variable">$pinned</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户可以请求create...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="拦截器响应" tabindex="-1"><a class="header-anchor" href="#拦截器响应"><span>拦截器响应</span></a></h3>
<p>到目前为止，我们只学习了拦截器（Gates）中返回布尔值的简单操作。但是，有时你需要的返回可能更复杂，比如错误消息。所以，你可以尝试使用<code v-pre>Illuminate\Auth\Access\Response</code>来构建你的拦截器（Gates）：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">isAdmin</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">deny</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'You must be an administrator.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你希望从拦截器（Gates）中返回响应时，使用<code v-pre>Gate::allows</code>方法，将仅返回一个简单的布尔值；同时，你还可以使用<code v-pre>Gate::inspect</code>方法来返回拦截器（Gates）中的所有响应值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">inspect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$response</span><span class="token operator">-></span><span class="token function">allowed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 行为进行授权...</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">echo</span> <span class="token variable">$response</span><span class="token operator">-></span><span class="token function">message</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在使用<code v-pre>Gate::authorize</code>方法时，如果操作未被授权，仍然会触发<code v-pre>AuthorizationException</code>, 用户验证（authorization）响应提供的错误消息，将传递给 HTTP 响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 行为进行授权...</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="自定义http响应状态" tabindex="-1"><a class="header-anchor" href="#自定义http响应状态"><span>自定义HTTP响应状态</span></a></h4>
<p>当一个操作通过 Gate 被拒绝时，返回一个<code v-pre>403</code>HTTP 响应；然而，有时返回一个可选的HTTP状态代码是有用的。你可以使用<code v-pre>Illuminate\Auth\Access\Response</code>类上的<code v-pre>denyWithStatus</code>静态构造函数自定义授权检查失败返回的HTTP状态代码：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">isAdmin</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">denyWithStatus</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>由于通过<code v-pre>404</code>响应隐藏资源是 Web 应用程序的常见模式，为了方便起见，提供了<code v-pre>denyAsNotFound</code>方法:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">isAdmin</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">denyAsNotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="拦截-gate-检查" tabindex="-1"><a class="header-anchor" href="#拦截-gate-检查"><span>拦截 Gate 检查</span></a></h3>
<p>有时，你可能希望将所有能力授予特定用户。你可以使用<code v-pre>before</code>方法定义一个闭包，在所有其他授权检查之前运行:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">before</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$ability</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isAdministrator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果<code v-pre>before</code>返回的是非 null 结果，则该返回将会被视为最终的检查结果。</p>
<p>你还可以使用<code v-pre>after</code>方法，来定义在所有授权拦截规则执行后，再次进行授权拦截规则判定：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">after</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$ability</span><span class="token punctuation">,</span> <span class="token keyword type-declaration">bool</span><span class="token operator">|</span><span class="token keyword type-declaration">null</span> <span class="token variable">$result</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$arguments</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isAdministrator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>类似于<code v-pre>before</code>方法，如果<code v-pre>after</code>闭包返回非空结果，则该结果将被视为授权检查的结果。</p>
<h3 id="内联授权" tabindex="-1"><a class="header-anchor" href="#内联授权"><span>内联授权</span></a></h3>
<p>有时，你可能希望确定当前经过身份验证的用户是否有权执行给定操作，而无需编写与该操作对应的专用拦截器。Laravel 允许你通过<code v-pre>Gate::allowIf</code>和<code v-pre>Gate::denyIf</code>方法执行这些类型的「内联」授权检查：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">allowIf</span><span class="token punctuation">(</span><span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isAdministrator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">denyIf</span><span class="token punctuation">(</span><span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">banned</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果该操作未授权或当前没有用户经过身份验证，Laravel 将自动抛出<code v-pre>Illuminate\Auth\Access\AuthorizationException</code>异常。<code v-pre>AuthorizationException</code>的实例会被 Laravel 的异常处理程序自动转换为 403 HTTP 响应：</p>
<h2 id="生成策略" tabindex="-1"><a class="header-anchor" href="#生成策略"><span>生成策略</span></a></h2>
<h3 id="生成策略-1" tabindex="-1"><a class="header-anchor" href="#生成策略-1"><span>生成策略</span></a></h3>
<p>策略是围绕特定模型或资源组织授权逻辑的类。例如，如果你的应用程序是博客，可能有一个<code v-pre>App\Models\Post</code>模型和一个相应的<code v-pre>App\Policies\PostPolicy</code>来授权用户操作，例如创建或更新帖子。</p>
<p>你可以使用<code v-pre>make:policy</code>Artisan 命令生成策略。生成的策略将放置在<code v-pre>app/Policies</code>目录中。如果应用程序中不存在此目录，Laravel 将自动创建：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan make:policy PostPolicy</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>make:policy</code>命令将生成一个空的策略类。如果要生成一个包含与查看、创建、更新和删除资源相关的示例策略方法的类，可以在执行命令时提供一个<code v-pre>--model</code>选项：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan make:policy PostPolicy <span class="token parameter variable">--model</span><span class="token operator">=</span>Post</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="注册策略" tabindex="-1"><a class="header-anchor" href="#注册策略"><span>注册策略</span></a></h3>
<p>创建了策略类之后，还需要对其进行注册。注册策略是告知 Laravel 在授权针对给定模型类型的操作时使用哪个策略。</p>
<p>新的 Laravel 应用程序中包含的<code v-pre>App\Providers\AuthServiceProvider</code>包含一个<code v-pre>policies</code>属性，它将 Eloquent 模型映射到其相应的策略。 注册策略将指示 Laravel 在授权针对给定 Eloquent 模型的操作时使用哪个策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Policies<span class="token punctuation">\</span>PostPolicy</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Providers<span class="token punctuation">\</span>AuthServiceProvider</span> <span class="token keyword">as</span> ServiceProvider<span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AuthServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 应用程序的策略映射。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@var</span> <span class="token class-name"><span class="token keyword">array</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">protected</span> <span class="token variable">$policies</span> <span class="token operator">=</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span> <span class="token operator">=></span> <span class="token class-name static-context">PostPolicy</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 注册任何应用程序身份验证/授权服务。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="策略自动发现" tabindex="-1"><a class="header-anchor" href="#策略自动发现"><span>策略自动发现</span></a></h4>
<p>只要模型和策略遵循标准的 Laravel 命名约定，Laravel 就可以自动发现策略，而不是手动注册模型策略。具体来说，策略必须位于包含模型的目录或其上方的「Policies」目录中。 因此，例如，模型可以放置在<code v-pre>app/Models</code>目录中，而策略可以放置在<code v-pre>app/Policies</code>目录中。在这种情况下，Laravel 将检查<code v-pre>app/Models/Policies</code>然后<code v-pre>app/Policies</code>中的策略。此外，策略名称必须与模型名称匹配并具有「策略」后缀。 因此，<code v-pre>User</code>模型将对应于<code v-pre>UserPolicy</code>策略类。</p>
<p>如果要自定义策略的发现逻辑，可以使用<code v-pre>Gate::guessPolicyNamesUsing</code>方法注册自定义策略发现回调。通常，应该从应用程序的<code v-pre>AuthServiceProvider</code>的<code v-pre>boot</code>方法调用此方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">guessPolicyNamesUsing</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$modelClass</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 返回给定模型的策略类的名称…</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong><br>
在<code v-pre>AuthServiceProvider</code>中显式映射的任何策略将优先于任何可能自动发现的策略。</p>
</blockquote>
<h2 id="编写策略" tabindex="-1"><a class="header-anchor" href="#编写策略"><span>编写策略</span></a></h2>
<h3 id="策略方法" tabindex="-1"><a class="header-anchor" href="#策略方法"><span>策略方法</span></a></h3>
<p>注册策略类后，可以为其授权的每个操作添加方法。例如，让我们在<code v-pre>PostPolicy</code>上定义一个 <code v-pre>update</code>方法，该方法确定给定的<code v-pre>App\Models\User</code>是否可以更新给定的<code v-pre>App\Models\Post</code>实例。</p>
<p>该<code v-pre>update</code>方法将接收一个<code v-pre>User</code>和一个<code v-pre>Post</code>实例作为其参数，并应返回<code v-pre>true</code>或<code v-pre>false</code>，指示用户是否有权更新给定的<code v-pre>Post</code>。因此，在本例中，我们将验证用户的<code v-pre>id</code>是否与 Post 上的<code v-pre>user_id</code>匹配：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Policies</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostPolicy</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 确定用户是否可以更新给定的帖子</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">bool</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以继续根据需要为策略授权的各种操作定义其他方法。例如，你可以定义<code v-pre>view</code>或<code v-pre>delete</code>方法来授权各种与<code v-pre>Post</code>相关的操作，但请记住，你可以自由地为策略方法命名任何你喜欢的名称。</p>
<p>如果你在 Artisan 控制台生成策略时使用了<code v-pre>--model</code>选项，它将包含用于<code v-pre>viewAny</code>、<code v-pre>view</code>、 <code v-pre>create</code>、<code v-pre>update</code>、<code v-pre>delete</code>、<code v-pre>restore</code>和<code v-pre>forceDelete</code>操作。</p>
<blockquote>
<p><strong>技巧</strong><br>
所有策略都通过 Laravel <a href="https://learnku.com/docs/laravel/10.x/container" target="_blank" rel="noopener noreferrer">服务容器</a>解析，允许你在策略的构造函数中键入任何需要的依赖项，以自动注入它们。</p>
</blockquote>
<h3 id="策略响应" tabindex="-1"><a class="header-anchor" href="#策略响应"><span>策略响应</span></a></h3>
<p>到目前为止，我们只检查了返回简单布尔值的策略方法。但是，有时你可能希望返回更详细的响应，包括错误消息。为此，你可以从你的策略方法返回一个<code v-pre>Illuminate\Auth\Access\Response</code>实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定用户是否可以更新给定的帖子。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">deny</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'你不拥有这个帖子。'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当从你的策略返回授权响应时，<code v-pre>Gate::allows</code>方法仍将返回一个简单的布尔值；但是，你可以使用<code v-pre>Gate::inspect</code>方法来获取返回的完整授权响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">inspect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$response</span><span class="token operator">-></span><span class="token function">allowed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 操作已被授权…</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">echo</span> <span class="token variable">$response</span><span class="token operator">-></span><span class="token function">message</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当使用<code v-pre>Gate::authorize</code>方法时，如果操作未被授权，该方法会抛出<code v-pre>AuthorizationException</code> ，授权响应提供的错误消息将传播到 HTTP 响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 该操作已授权通过...</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="自定义http响应状态-1" tabindex="-1"><a class="header-anchor" href="#自定义http响应状态-1"><span>自定义HTTP响应状态</span></a></h4>
<p>当一个操作通过策略方法被拒绝时，返回一个<code v-pre>403</code>HTTP 响应;然而，有时返回一个可选的 HTTP 状态代码是有用的。你可以使用<code v-pre>Illuminate\Auth\Access\Response</code>类上的<code v-pre>denyWithStatus</code>静态构造函数自定义授权检查失败返回的 HTTP 状态代码:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定用户是否可以更新给定的帖子。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">denyWithStatus</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>由于通过<code v-pre>404</code>响应隐藏资源是 Web 应用程序的常见模式，为了方便起见，提供了<code v-pre>denyAsNotFound</code>方法:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定用户是否可以更新给定的帖子。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">denyAsNotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="无需传递模型的方法" tabindex="-1"><a class="header-anchor" href="#无需传递模型的方法"><span>无需传递模型的方法</span></a></h3>
<p>一些策略方法只接收当前经过身份验证的用户实例，最常见的情况是给 <code v-pre>create</code> 方法做授权。例如，如果你正在创建一个博客，你可能希望确定一个用户是否被授权创建任何文章，在这种情况下，你的策略方法应该只期望接收一个用户实例：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定给定用户是否可以创建文件</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">create</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">bool</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">role</span> <span class="token operator">==</span> <span class="token string single-quoted-string">'writer'</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="guest-用户" tabindex="-1"><a class="header-anchor" href="#guest-用户"><span>Guest 用户</span></a></h3>
<p>默认情况下，如果传入的 HTTP 请求不是经过身份验证的用户发起的，那么所有的拦截器（gates）和策略（policies）会自动返回<code v-pre>false</code>。但是，你可以通过声明一个「optional」类型提示或为用户参数定义提供一个<code v-pre>null</code>默认值，从而允许这些授权检查通过你的拦截器（gates）和策略（policies）：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Policies</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostPolicy</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 确定用户是否可以更新给定的文章</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token operator">?</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">bool</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">?-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="策略过滤器" tabindex="-1"><a class="header-anchor" href="#策略过滤器"><span>策略过滤器</span></a></h3>
<p>对于某些用户，你可能希望给他授权给定策略中的所有操作。为了实现这一点，你可以在策略上定义一个<code v-pre>before</code>方法。该<code v-pre>before</code>方法将在策略上的所有方法之前执行，这样就使你有机会在实际调用预期的策略方法之前就已经授权了操作。该功能常用于授权应用程序管理员来执行任何操作：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 执行预先授权检查</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">before</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$ability</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">bool</span><span class="token operator">|</span><span class="token keyword type-declaration">null</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isAdministrator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token constant">null</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想拒绝特定类型用户的所有授权检查，那么你可以从<code v-pre>before</code>方法返回<code v-pre>false</code>。如果返回<code v-pre>null</code>，则授权检查将通过策略方法进行。</p>
<blockquote>
<p><strong>注意</strong><br>
如果策略类中不包含名称与被检查能力的名称相匹配的方法，则不会调用策略类的<code v-pre>before</code>方法。</p>
</blockquote>
<h2 id="使用策略进行授权操作" tabindex="-1"><a class="header-anchor" href="#使用策略进行授权操作"><span>使用策略进行授权操作</span></a></h2>
<h3 id="通过用户模型" tabindex="-1"><a class="header-anchor" href="#通过用户模型"><span>通过用户模型</span></a></h3>
<p>Laravel 应用程序中的<code v-pre>App\Models\User</code>型提供了两个用于授权操作的方法：<code v-pre>can</code>和<code v-pre>cannot</code>。<code v-pre>can</code>和<code v-pre>cannot</code>方法接收你希望授权的操作名称和相关模型。例如，让我们确定一个用户是否被授权更新给定的<code v-pre>App\Models\Post</code>模型，这通常在控制器方法中实现：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 更新给定的帖子。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cannot</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token function">abort</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 更新帖子...</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果为给定模型<a href="#registering-policies">注册了策略</a>，该<code v-pre>can</code>方法将自动调用适当的策略并返回布尔值；如果没有为模型注册策略，该<code v-pre>can</code>方法将尝试调用基于 Gate 的闭包，该闭包将匹配给定的操作名称。</p>
<h4 id="不需要指定模型的操作" tabindex="-1"><a class="header-anchor" href="#不需要指定模型的操作"><span>不需要指定模型的操作</span></a></h4>
<p>请记住，某些操作可能对应着「不需要模型实例」的策略方法，比如<code v-pre>create</code>。在这些情况下，你可以将类名传递给<code v-pre>can</code>方法，类名将用于确定在授权操作时使用哪个策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 创建一个帖子。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">store</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">cannot</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token function">abort</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 创建帖子…</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="通过控制器辅助函数" tabindex="-1"><a class="header-anchor" href="#通过控制器辅助函数"><span>通过控制器辅助函数</span></a></h3>
<p>除了给<code v-pre>App\Models\User</code>模型提供了有用方法，Laravel 还给任何控制器提供了一个有用的 <code v-pre>authorize</code> 方法，这些控制器要继承（<code v-pre>extends</code>）<code v-pre>App\Http\Controllers\Controller</code>基类。</p>
<p>与<code v-pre>can</code>方法一样，<code v-pre>authorize</code>方法接收你希望授权的操作名称和相关模型，如果该操作未被授权，该方法将抛出<code v-pre>Illuminate\Auth\Access\AuthorizationException</code>异常，Laravel 的异常处理程序将自动将该异常转换为一个带有 403 状态码的 HTTP 响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 更新指定的博客文章</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@throws</span> <span class="token class-name"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>AuthorizationException</span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 当前用户可以更新博客文章…</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="不需要指定模型的操作-1" tabindex="-1"><a class="header-anchor" href="#不需要指定模型的操作-1"><span>不需要指定模型的操作</span></a></h4>
<p>如前所述，一些策略方法 如<code v-pre>create</code>不需要模型实例，在这些情况下，你应该给<code v-pre>authorize</code>方法传递一个类名，该类名将用来确定在授权操作时使用哪个策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>RedirectResponse</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 创建一个新的博客文章。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@throws</span> <span class="token class-name"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>AuthorizationException</span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">create</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 当前用户可以创建博客帖子…</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="授权资源控制器" tabindex="-1"><a class="header-anchor" href="#授权资源控制器"><span>授权资源控制器</span></a></h4>
<p>如果你正在使用<a href="https://learnku.com/docs/laravel/10.x/controllers#resource-controllers" target="_blank" rel="noopener noreferrer">资源控制器</a>，你可以在控制器的构造方法中使用<code v-pre>authorizeResource</code>方法，该方法将把适当的<code v-pre>can</code>中间件定义附加到资源控制器的方法上。</p>
<p>该<code v-pre>authorizeResource</code>方法的第一个参数是模型的类名，第二个参数是包含模型 ID 的 路由/请求参数的名称。你应该确保你的<a href="https://learnku.com/docs/laravel/10.x/controllers#resource-controllers" target="_blank" rel="noopener noreferrer">资源控制器</a>是使用 <code v-pre>--model</code> 标志创建的，这样它才具有所需的方法签名和类型提示。</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 创建控制器实例</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">authorizeResource</span><span class="token punctuation">(</span><span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'post'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>以下控制器方法将映射到其相应的策略方法。当请求被路由到给定的控制器方法时，会在控制器方法执行之前自动调用相应的策略方法：</p>
<table>
<thead>
<tr>
<th>控制器方法</th>
<th>策略方法</th>
</tr>
</thead>
<tbody>
<tr>
<td>index</td>
<td>viewAny</td>
</tr>
<tr>
<td>show</td>
<td>view</td>
</tr>
<tr>
<td>create</td>
<td>create</td>
</tr>
<tr>
<td>store</td>
<td>create</td>
</tr>
<tr>
<td>edit</td>
<td>update</td>
</tr>
<tr>
<td>update</td>
<td>update</td>
</tr>
<tr>
<td>destroy</td>
<td>delete</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>技巧</strong><br>
你可以使用带有<code v-pre>make:policy</code>带有 <code v-pre>--model</code>选项的命令，快速的为给定模型生成一个策略类：<code v-pre>php artisan make:policy PostPolicy --model=Post</code>。</p>
</blockquote>
<h3 id="通过中间件" tabindex="-1"><a class="header-anchor" href="#通过中间件"><span>通过中间件</span></a></h3>
<p>Laravel 包含一个中间件，可以在传入的请求到达路由或控制器之前对操作进行授权。默认情况下，<code v-pre>Illuminate\Auth\Middleware\Authorize</code>中间件会在<code v-pre>App\Http\Kernel</code>中的<code v-pre>can</code>键中被指定。让我们来看一个使用<code v-pre>can</code>中间件授权用户更新博客文章的例子：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/{post}'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 当前用户可以更新帖子…</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'can:update,post'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在这个例子中，我们给<code v-pre>can</code>中间件传递了两个参数。第一个是我们希望授权操作的名称，第二个是我们希望传递给策略方法的路由参数。在这个例子中，当我们使用了<a href="https://learnku.com/docs/laravel/10.x/routing#implicit-binding" target="_blank" rel="noopener noreferrer">隐式模型绑定</a>后，一个<code v-pre>App\Models\Post</code>模型就将被传递给对应的策略方法。如果用户没有被授权执行给定操作的权限，那么中间件将会返回一个带有 403 状态码的 HTTP 响应。</p>
<p>为了方便起见，你也可以使用<code v-pre>can</code>方法将<code v-pre>can</code>中间件绑定到你的路由上：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/{post}'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 当前用户可以更新文章...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'post'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="不需要指定模型的操作-2" tabindex="-1"><a class="header-anchor" href="#不需要指定模型的操作-2"><span>不需要指定模型的操作</span></a></h4>
<p>同样的，一些策略方法不需要模型实例，比如<code v-pre>create</code>。在这些情况下，你可以给中间件传递一个类名。这个类名将用来确定在授权操作时使用哪个策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 当前用户可以创建文章...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'can:create,App\Models\Post'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在一个中间件中定义整个类名会变得难以维护。因此，你也可以选择使用<code v-pre>can</code>方法将<code v-pre>can</code>中间件绑定到你的路由上：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 当前用户可以创建文章</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="通过-blade-模板" tabindex="-1"><a class="header-anchor" href="#通过-blade-模板"><span>通过 Blade 模板</span></a></h3>
<p>当编写 Blade 模板时，你可能希望只展示给用户有权限操作的数据。例如，你可能希望当用户具有更新文章的权限时才展示更新博客文章的表单。在这种情况下，你可以使用<code v-pre>@can</code>和<code v-pre>@cannot</code>指令：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@can('update', $post)</span>
<span class="line">    &lt;!-- 当前用户可更新的文章... --&gt;</span>
<span class="line">@elsecan('create', App\Models\Post::class)</span>
<span class="line">    &lt;!-- 当前用户可创建新文章... --&gt;</span>
<span class="line">@else</span>
<span class="line">    &lt;!-- ... --&gt;</span>
<span class="line">@endcan</span>
<span class="line"></span>
<span class="line">@cannot('update', $post)</span>
<span class="line">    &lt;!-- 当前用户不可更新的文章... --&gt;</span>
<span class="line">@elsecannot('create', App\Models\Post::class)</span>
<span class="line">    &lt;!-- 当前用户不可创建新文章... --&gt;</span>
<span class="line">@endcannot</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这些指令是编写<code v-pre>@if</code>和<code v-pre>@unless</code>语句的快捷方式。上面的<code v-pre>@can</code>和<code v-pre>@cannot</code>语句相当于下面的语句：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@if (Auth::user()-&gt;can('update', $post))</span>
<span class="line">    &lt;!-- 当前用户可更新的文章... --&gt;</span>
<span class="line">@endif</span>
<span class="line"></span>
<span class="line">@unless (Auth::user()-&gt;can('update', $post))</span>
<span class="line">    &lt;!-- 当前用户不可更新的文章... --&gt;</span>
<span class="line">@endunless</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你还可以确定一个用户是否被授权从给定的操作数组中执行任何操作，要做到这一点，可以使用<code v-pre>@canany</code>指令：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@canany(['update', 'view', 'delete'], $post)</span>
<span class="line">    &lt;!-- 当前用户可以更新、查看、删除文章... --&gt;</span>
<span class="line">@elsecanany(['create'], \App\Models\Post::class)</span>
<span class="line">    &lt;!-- 当前用户可以创建新文章... --&gt;</span>
<span class="line">@endcanany</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="不需要执行模型的操作" tabindex="-1"><a class="header-anchor" href="#不需要执行模型的操作"><span>不需要执行模型的操作</span></a></h4>
<p>像大多数其他授权方法一样，如果操作不需要模型实例，你可以给<code v-pre>@can</code>和<code v-pre>@cannot</code>指令传递一个类名：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@can('create', App\Models\Post::class)</span>
<span class="line">    &lt;!-- 当前用户可以创建文章... --&gt;</span>
<span class="line">@endcan</span>
<span class="line"></span>
<span class="line">@cannot('create', App\Models\Post::class)</span>
<span class="line">    &lt;!-- 当前用户不能创建文章... --&gt;</span>
<span class="line">@endcannot</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="提供额外的上下文" tabindex="-1"><a class="header-anchor" href="#提供额外的上下文"><span>提供额外的上下文</span></a></h3>
<p>在使用策略授权操作时，可以将数组作为第二个参数传递给授权函数和辅助函数。数组中的第一个元素用于确定应该调用哪个策略，其余的数组元素作为参数传递给策略方法，并可在作出授权决策时用于额外的上下文中。例如，考虑下面的 <code v-pre>PostPolicy</code> 方法定义，它包含一个额外的 <code v-pre>$category</code> 参数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确认用户是否可以更新给定的文章。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">,</span> <span class="token keyword type-hint">int</span> <span class="token variable">$category</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">bool</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span> <span class="token operator">&amp;&amp;</span></span>
<span class="line">           <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">canUpdateCategory</span><span class="token punctuation">(</span><span class="token variable">$category</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当尝试确认已验证过的用户是否可以更新给定的文章时，我们可以像这样调用此策略方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 更新给定的博客文章</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@throws</span> <span class="token class-name"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>AuthorizationException</span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">RedirectResponse</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token variable">$post</span><span class="token punctuation">,</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token property">category</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 当前用户可以更新博客文章...</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/10.x/authorization/14877" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/10.x/au...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/10.x/authorization/14877" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/10.x/au...</a></p>
</blockquote>
</div></template>


